import json

from alipay import AliPay
from django.conf import settings
from django.http import JsonResponse
from django.shortcuts import render, redirect
from django.views.generic import View
from django_redis import get_redis_connection

from user.models import Address
from goods.models import GoodsSKU
from datetime import datetime
from django.db import transaction
from order.models import OrderInfo, OrderGoods
from decimal import Decimal
import ssl
ssl._create_default_https_context = ssl._create_unverified_context


class OrderPlaceView(View):

    def post(self, request):
        # 获取表单数据 携带了下订单商品id值
        sku_ids = request.POST.getlist('sku_ids')
        # 查询地址 当前登录用户的地址信息
        user = request.user
        addrs = Address.objects.filter(user=user)
        # 查询商品
        skus = GoodsSKU.objects.filter(id__in=sku_ids)
        # 从redis 中获取商品数量
        conn = get_redis_connection('carts')
        sku_count = conn.hgetall('sku_count_%d' % user.id)
        # 转化redis数据
        cart_dict = {}
        for key, value in sku_count.items():
            cart_dict[int(key)] = int(value)
        total_count = 0
        total_price = 0
        for sku in skus:
            # 购买的数量
            sku.count = cart_dict[sku.id]
            # 购买商品的价格小计
            sku.amount = cart_dict[sku.id] * sku.price
            # 购买商品的总量累加
            total_count += cart_dict[sku.id]
            # 购买商品的总价累加
            total_price += cart_dict[sku.id] * sku.price
        # str_data = '+'
        # for id in sku_ids:
        #     str_data += id
        #     str_data += '+'

        # 将数据写入redis
        conn = get_redis_connection('carts')
        conn.lpush('sku_ids_%d' % user.id, *sku_ids)

        context = {
            'addrs': addrs,
            'skus': skus,
            'total_count': total_count,
            'total_price': total_price,
            'total_pay': total_price + 10,
            'sku_ids': sku_ids,
            "transit_price": 10

        }

        return render(request, 'place_order.html', context)


class OrderCommitView(View):

    def post(self, request):
        # 1、获取数据 地址id 支付方式
        data_dict = request.POST
        address_id = int(data_dict.get('addr_id'))
        pay_method = int(data_dict.get('pay_method'))
        # 2、获取当前登录用户数据 在保存地址基本信息时需要用到数据
        user = request.user
        # 3、验证数据
        if not all([address_id, pay_method]):
            return JsonResponse({'res': 400, 'errmsg': "数据不完整"}, status=400)
        # 4、判断地址是否存在
        try:
            address = Address.objects.get(id=address_id)
        except:
            return JsonResponse({'res': 400, 'errmsg': "地址不存在"}, status=400)
        # 5、生成订单编号 时间+用户id
        order_id = datetime.now().strftime('%Y%m%d%H%M%S') + '%09d' % user.id
        # 当要进行数据操作时，开启事务
        with transaction.atomic():
            # 事务使用 1、设置保存点，在出现错误时回滚到保存点
            save_point = transaction.savepoint()
            try:
                # 6、保存订单基本信息表
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    addr=address,
                    total_count=0,
                    total_price=Decimal(0),  # 总价
                    transit_price=Decimal(10),  # 运费
                    pay_method=pay_method,
                    order_status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == '3' else
                    OrderInfo.ORDER_STATUS_ENUM['UNSEND']  # 根据支付方式确认订单状态
                )
                # 7、获取订单商品，商品从哪里来？从reids中获取选中状态的商品id，选中的商品是用户需要购买下单商品
                # 连接rdis
                conn = get_redis_connection('carts')
                sku_ids = conn.lrange('sku_ids_%d' % request.user.id, 0, 1000)
                # 获取商品的购买数据量 获取到的值是bytes类型
                sku_count = conn.hgetall('sku_count_%d' % user.id)
                sku_ids = set(sku_ids)
                # 将bytes类型转化为int
                data_dict = {}
                for sku_id, count in sku_count.items():
                    data_dict[int(sku_id)] = int(count)
                # 8、根据商品id查询商品表获取商品信息
                for sku_id in sku_ids:
                    while True:
                        # 8-1 查询sku数据
                        sku = GoodsSKU.objects.get(id=sku_id)
                        # 8-2 下单之后，商品的销量和库存量也要进行变化
                        old_salse = sku.sales  # sku的销量
                        old_stock = sku.stock  # sku的库存
                        # 8-3、购买的数量不能大于库存
                        count = data_dict[sku.id]
                        if count > old_stock:
                            # 库存不足
                            transaction.savepoint_rollback(save_point)
                            return JsonResponse({'res': 400, 'errmsg': '库存不足'}, status=400)
                        # 8-4、修改sku商品库存和销量
                        # sku.stock = old_stock - count
                        # sku.sales = old_salse + count
                        # sku.save()
                        # 乐观锁使用，在更新数据前再次查询库存是否发生变化，如果发生变化，其他用户已经修改库存，则当前用户不能修改库存，重新只从查询原始库存操作，再次判断购买数量
                        res = GoodsSKU.objects.filter(id=sku.id, stock=old_stock).update(stock=old_stock - count,
                                                                                         sales=old_salse + count)
                        # 判断返回结果 res = 1 说明更行成功 res = 0 更新失败
                        if res == 0:
                            continue
                        # 8-6、累加商品价格和数量 订单基本信息表需要保存购买的商品的总数和总价
                        order.total_count += count
                        order.total_price += count * sku.price
                        # 9、保存订单商品表
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=count,
                            price=sku.price
                        )

                        # 跳出循环
                        break
                # 当for循环结束后所有选中状态的商品已经处理完成，要累加的总价基础上在添加一个运费
                order.total_price += order.transit_price
                order.save()
            except Exception as e:
                print(e)
                # 捕获到异常，说明有代码出现问题需要回滚到保存点
                transaction.savepoint_rollback(save_point)
            # 没有捕获到异常 提交
            transaction.savepoint_commit(save_point)
        # 10、购物车中的选中状态的商品已经下单，就需要将购物车中选中状态商品进行清除  sku_ids是选中状态的sku_id
        conn.hdel('sku_count_%d' % user.id, *sku_ids)
        conn.delete('sku_ids_%d' % request.user.id)

        return JsonResponse({'res': 5})


class OrderPayView(View):

    def post(self, request):
        order_id = request.POST.get('order_id')
        # 获取订单信息
        try:
            order = OrderInfo.objects.get(order_id=order_id, order_status=1)
        except:
            return JsonResponse({
                'res': 400,
                'errmsg': '订单不存在',
            }, status=400)

        # 1、初始化生成支付对象
        app_private_key_string = open(
            "/Users/august/Desktop/ttsx_project/dailyfresh/apps/order/app_private_key.pem").read()
        alipay_public_key_string = open(
            "/Users/august/Desktop/ttsx_project/dailyfresh/apps/order/app_public_key.pem").read()

        alipay = AliPay(
            appid="2016091300505120",
            app_notify_url=settings.ALIPAY_RETURN_URL,  # 默认回调url
            app_private_key_string=app_private_key_string,
            # 指定美多私钥
            # 支付宝的公钥，验证支付宝回传消息使用，不是你自己的公钥,
            alipay_public_key_string=alipay_public_key_string,
            sign_type="RSA2",  # RSA 或者 RSA2
            debug=True  # 默认False
        )
        # 2、调用对象方法生成跳转链接 api_alipay_trade_page_pay这个方法只是生成了跳转链接所需要的查询字符串数据，需要和支付网关进行拼接
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=str(order_id),  # 点单编号
            total_amount=str(order.total_price),  # 订单总价
            subject='天天生鲜',  # 看到的商家名称
            return_url=settings.ALIPAY_RETURN_URL,  # 跳转链接
        )
        # 拼接完整的支付地址
        alipay_url = 'https://openapi.alipaydev.com/gateway.do?' + order_string
        return JsonResponse({
            'res': 3,
            'pay_url': alipay_url
        })


class OrderCheckView(View):

    def post(self, request):

        order_id = request.POST.get('order_id')
        # 获取订单信息
        try:
            order = OrderInfo.objects.get(order_id=order_id, order_status=1)
        except:
            return JsonResponse({
                'res': 400,
                'errmsg': '订单不存在',
            }, status=400)

        # 1、初始化生成支付对象
        app_private_key_string = open(
            "/Users/august/Desktop/ttsx_project/dailyfresh/apps/order/app_private_key.pem").read()
        alipay_public_key_string = open(
            "/Users/august/Desktop/ttsx_project/dailyfresh/apps/order/app_public_key.pem").read()

        alipay = AliPay(
            appid="2016091300505120",
            app_notify_url=settings.ALIPAY_RETURN_URL,  # 默认回调url
            app_private_key_string=app_private_key_string,
            # 指定美多私钥
            # 支付宝的公钥，验证支付宝回传消息使用，不是你自己的公钥,
            alipay_public_key_string=alipay_public_key_string,
            sign_type="RSA2",  # RSA 或者 RSA2
            debug=True  # 默认False
        )
        # 请求支付查询该订单是否支付成功

        try:
            result = alipay.api_alipay_trade_query(out_trade_no=order_id)
            if result.get("trade_status", "") == "TRADE_SUCCESS":
                order.order_status = 4
                order.save()
        except Exception as e:
            print(e)
        return JsonResponse({
            'res': 3,
        })


class OrderCommentView(View):

    def get(self, request, order_id):
        # order_id = request.POST.get('order_id')
        # 获取订单信息
        try:
            order = OrderInfo.objects.get(order_id=order_id)
        except:
            return JsonResponse({
                'res': 400,
                'errmsg': '订单不存在',
            }, status=400)
        order.order_skus = order.ordergoods_set.all()
        context = {'order': order}
        return render(request, 'order_comment.html', context)

    def post(self, request, order_id):
        # order_id = request.POST.get('order_id')
        content_1 = request.POST.get('content_1')
        sku_1 = request.POST.get('sku_1')
        # 获取订单信息
        try:
            order = OrderInfo.objects.get(order_id=order_id)
        except:
            return JsonResponse({
                'res': 400,
                'errmsg': '订单不存在',
            }, status=400)
        goods = order.ordergoods_set.get(sku_id=sku_1)
        goods.comment = content_1
        goods.save()
        order.order_skus = order.ordergoods_set.all()
        context = {'order': order}
        return render(request, 'order_comment.html', context)
